package cn.kgc.reflect;

import cn.kgc.dto.AddSysUserDTO;

import javax.validation.constraints.NotBlank;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * <p>反射</p>
 *
 * @author 石浩杰
 * @since 2022年09月26日 10:38
 * 反射:在程序运行过程中，确定加载哪些类，获得类的相关信息
 *
 * 反射类和方法：
 *
 */
public class Demo1 {
    //在程序运行的过程中获得类的名字


    //Constructor类:类中构造方法的信息
    public static void main(String[] args){
        //通过反射技术创建AddSysUserDTO类的对象，给对象中的username属性赋值,获得username属性值
        try {
            Class<AddSysUserDTO> class1=AddSysUserDTO.class;
            AddSysUserDTO addSysUserDTO=class1.newInstance();
            //通过反射给name属性赋值
            Field nameField=class1.getDeclaredField("name");
            nameField.setAccessible(true);
            //调用nameFiled属性中的set方法
            //给addSysUserDTO对象中的name属性赋值scott
            nameField.set(addSysUserDTO,"scott");
            //通过反射获得name属性值
            String name=(String) nameField.get(addSysUserDTO);
            System.out.println(name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void extracted3() {
        Class class1=AddSysUserDTO.class;
        //忽略访问修饰符获得该类的所有构造方法
        Constructor [] constructors=class1.getDeclaredConstructors();
        try {
            //获得AddSysUserDTO类中 四个参数都是String类型的构造方法
            Constructor constructor=
                    class1.getDeclaredConstructor(String.class,String.class,String.class,String.class);
            //执行四个桉树的构造方法
            AddSysUserDTO addSysUserDTO=(AddSysUserDTO) constructor.newInstance("scott","111@qq.com","123","123");
            //使用无参构造方法创建对象
            AddSysUserDTO addSysUserDTO1=(AddSysUserDTO) class1.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //Method类:对应的是类中的方法信息
    //getDeclaredMethods:忽略访问修饰符 获得类中所有方法
    //getDeclaredMethod(String name,Class...):忽略访问修饰符，根据name和Class获得单个方法
    //name方法名 方法后面参数的类型

    //invoke(instance,argumentValue)
    //通过反射技术执行方法。instance方法对应的对象,argumentValue参数的值

    //setAccessible(boolean flag)
    //isAnnotationPresent判断方法上是否有该注解
    //getAnnotation获得该注解
    private static void extracted2() {
        Class class1=AddSysUserDTO.class;
        Method [] methods=class1.getDeclaredMethods();//忽略访问修饰符，获得方法
        for (Method method : methods) {
            System.out.println(method.getName());
        }
        try {
            Method method1=class1.getDeclaredMethod("method1", String.class);
            System.out.println("通过反射获得的单个方法:"+method1.getName());
            //通过反射执行method1方法(invoke)
            //调用AddSysUserDTO类的无参对象
            AddSysUserDTO addSysUserDTO=(AddSysUserDTO) class1.newInstance();
            //通过反射执行method1方法，调用的是invoke方法 invoke方法需要传入两个参数
            //第一个参数是方法所在类的对象，第二个参数是方法需要传入的参数值
            //methode1方法访问修饰符是私有的，想调用私有的，设置值为true
            method1.setAccessible(true);
            method1.invoke(addSysUserDTO,"HelloWorld");
            if (method1.isAnnotationPresent(NotBlank.class)){//判断方法上是否有NotBlank注解
                NotBlank notBlank=method1.getAnnotation(NotBlank.class);
                String message=notBlank.message();//获得NotBlank注解上的message上的值
                System.out.println(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //Field类 对应的是类中的属性的信息
    //getFields方法获得的是访问修饰符是public的属性的信息
    //getDeclaredFields方法获得的是忽略访问修饰符的属性的信息
    //getDeclaredField(String name) 根据属性的名字，忽略访问修饰符获得属性的信息
    //isAnnotationPresent 判断属性上是否含有某个注解
    private static void extracted1() {
        Class class1=AddSysUserDTO.class;
        Field [] fields1=class1.getFields();//获得
        Field [] fields2=class1.getDeclaredFields(); //类中的属性是4个
        System.out.println(fields1.length);
        System.out.println(fields2.length);
        //获得AddSysUserDTO类中name属性的信息
        try {
            Field userNameField=class1.getDeclaredField("name");
            System.out.println("获得username属性的信息"+userNameField);
            //判断name属性上是否有NotBlank注解
            boolean flag=userNameField.isAnnotationPresent(NotBlank.class);
            System.out.println("判断username属性上是否有NotBlank注解"+flag);
            //获得name属性上的NotBlank注解信息
            Annotation annotation=userNameField.getDeclaredAnnotation(NotBlank.class);
            System.out.println("name属性上NotBlank注解信息是:"+annotation);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得一个类的信息的三种方式
     * 方式1:通过class属性
     * 方式2:通过Class.forName
     * 方式3:通过类的对象的getClass()
     * Class类是反射的基础类，类的所有的信息都在Class类上
     */
    private static void extracted() {
        Class class1= AddSysUserDTO.class;
        Class class2=null;
        try {
            class2=Class.forName("cn.kgc.dto.AddSysUserDTO");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        AddSysUserDTO addSysUserDTO3=new AddSysUserDTO();
        Class class3=addSysUserDTO3.getClass();
        System.out.println("打印类的名字:"+class1.getName());
        System.out.println("打印类的名字:"+class2.getSimpleName());
        System.out.println("打印类的名字:"+class3.getName());
        System.out.println("打印其父类的名字:"+class1.getSuperclass().getSimpleName());
    }
}
